<template>
  <FaPanel class="fa-thumbs" :class="{ 'is-only': docs.length === 1 }">
    <template #header>
      <slot name="header" v-bind="{ docs: state.docs }">
        <h3 class="fa-panel__hd-title">{{ title }}</h3>
        <p class="fa-panel__hd-desc">共{{ docs.length }}份</p>
      </slot>
    </template>

    <div ref="body" v-lazy-container="{ selector: '.thumb-page-img', loading: loadingImage }" class="fa-thumbs__body">
      <div
        v-for="(item, index) in state.docs"
        :key="item.id"
        class="thumb-doc"
        :class="{ 'is-open': layout.activeDocIndex === index, 'is-active': docIndex === index }"
      >
        <div class="thumb-doc__hd" @click="layout.toggleDoc(index)">
          <slot name="doc" v-bind="{ docs, doc: item, index }">
            <i class="thumb-doc__hd-arrow fa-icon-caret-bottom"></i>
            <i class="thumb-doc__hd-icon fa-icon-paper"></i>
            <h3 class="thumb-doc__hd-text" :title="item.name">{{ item.name }}</h3>
          </slot>
        </div>

        <!-- <ul v-if="layout.activeDocIndex === index && state.doc" ref="scrollers" class="thumb-pages">
          <li
            v-for="page in state.doc.pages"
            :key="`${item.id}-${page.p}`"
            class="thumb-page"
            :class="{ cur: state.pageIndex == page.p }"
            @click="selectPage(page.p)"
          >
            {{ void (width = thumbWidth + 'px') }}
            {{ void (height = getThumbHeight(page) + 'px') }}

            <slot
              name="page"
              v-bind="{
                docs,
                doc: item,
                page,
                width,
                height
              }"
            >
              <img
                :data-src="getPageImg(state.doc, page)"
                class="thumb-page-img"
                :draggable="false"
                :style="{ width, height }"
              />
              <div class="thumb-page-count">{{ page.p + 1 }}/{{ item.count }}</div>
            </slot>
          </li>
        </ul> -->
      </div>
    </div>
  </FaPanel>
</template>

<script lang="ts">
import { computed, defineComponent, nextTick, onBeforeUpdate, PropType, reactive, Ref, ref, toRef, watch } from 'vue'
import useDocState from '../contract/useDocState'
import config from '@/config'
import { Viewer, DocData, PageData } from '@/types'
import { scrollIntoView } from '@/utils'
import useScroll from '@/utils/compositions/useScroll'

/** 布局和操作控制 */
function useThumbsLayout({
  docIndex
}: {
  /** 文档索引 */
  docIndex: Ref<number>
}) {
  const c = reactive({
    /** 展开的文档索引 */
    activeDocIndex: 0,

    /** 切换文档展开 */
    toggleDoc(index: number) {
      c.activeDocIndex = index === c.activeDocIndex ? -1 : index
      docIndex.value = index
    },

    /** 选择文档 */
    selectDoc(index: number) {
      docIndex.value = index
    }
  })

  /** 文档索引变更后更新展开 */
  watch(docIndex, () => {
    c.activeDocIndex = docIndex.value
  })

  return c
}

/** 文档列表 */
export default defineComponent({
  name: 'FaThumbs',

  props: {
    /** 标题 */
    title: {
      type: String,
      default: '文档列表'
    },

    /** 文档列表 - 用于批量文档 */
    docs: {
      type: Array as PropType<DocData[]>,
      default: () => []
    },

    /** 当前文档索引，需要添 `.sync` 双向同步 */
    docIndex: {
      type: Number,
      default: 0
    },

    /**
     * 页面图片地址
     * @description 如果文档页面数据 `PageData` 未设置 `src`，则可使用该选项统一设置文档图片地址
     * @version v1.4.0
     */
    pageSrc: Function as PropType<(doc: DocData, page: PageData) => string | void>,

    /** 缩略图展示宽度 */
    thumbWidth: {
      type: Number,
      default: 120
    },

    /** 文档查看组件 */
    viewer: {
      type: Object as PropType<Viewer>
    }
  },

  emits: [
    /** 文档选择 `selectDoc(index: number, doc: DocData)` */
    'select-doc',
    /** 页面选择 `selectPage(index: number), page: PageData` */
    'select-page',

    /** docIndex.sync */
    'update:docIndex'
  ],

  setup(props, { emit }) {
    const viewerScroll = computed(() => props.viewer?.scroll)

    /** 文档列表 */
    const docs = toRef(props, 'docs')

    /** 文档索引 */
    const docIndex = computed({
      set: (index: number) => emit('update:docIndex', index),
      get: () => props.docIndex
    })

    const state = useDocState(docs, docIndex)

    /** 当前文档 */
    const doc = toRef(state, 'doc')

    /** 滚动条节点列表 */
    const scrollers = ref([])

    const layout = useThumbsLayout({
      docIndex
    })

    const body = ref(null as HTMLElement | null)

    /** 当前滚动节点 */
    const scroller = computed(() => scrollers.value[0])

    const scroll = useScroll(scroller)

    /** 确保在每次更新之前重置ref */
    onBeforeUpdate(() => (scrollers.value = []))

    /** 文档切换 */
    watch(docIndex, index => {
      state.pageIndex = 0
      doc.value && emit('select-doc', index, doc.value)
    })

    watch(doc, val => {
      /** 找不到文档则取最后一个 */
      if (!val) {
        docIndex.value = layout.activeDocIndex = docs.value.length - 1
        doc.value && emit('select-doc', docIndex.value, doc.value)
      }

      /** 文档切换后滚动到顶部 */
      nextTick(() => {
        scroll.scrollToTop(false)

        setTimeout(() => {
          if (body.value) scrollIntoView(body.value.querySelector('.is-open') as HTMLElement, body.value)
        }, 401)
      })
    })

    /** 同步查看器滚动 */
    watch(
      () => viewerScroll.value?.state.ratio,
      ratio => {
        const vScroll = viewerScroll.value

        if (ratio === undefined || !scroller.value || !vScroll) return

        const { pageIndex, syncLocked } = vScroll

        if (!syncLocked) {
          state.pageIndex = pageIndex
          scroll.scrollToRatio(ratio, false)
        }
      }
    )

    return {
      state,
      scroll,
      layout,
      doc,
      body,
      scrollers,

      /** 加载中图片 */
      loadingImage: config.loadingImage,

      /** 获取文档页面图片地址 */
      getPageImg(doc: DocData, page: PageData) {
        return page.src || props.pageSrc?.(doc, page) || props.viewer?.pageSrc?.(doc, page) || ''
      },

      /** 获取缩略图高度 */
      getThumbHeight(page: PageData) {
        return Math.floor(page.h * (props.thumbWidth / page.w))
      },

      /** 选择页面 */
      selectPage(index: number) {
        state.pageIndex = index

        emit('select-page', index, state.pages[index])

        const viewerScroll = props.viewer?.scroll

        // 查看器滚动
        if (viewerScroll) {
          viewerScroll.lockScrollSync()
          viewerScroll.scrollToPage(index)
        }
      }
    }
  }
})
</script>

<style lang="scss">
/** 左右间距 */
$space: 16px;
$doc-item-height: 36px;

.fa-thumbs {
  position: relative;
  box-sizing: border-box;
  height: 100%;
  background: #fff;
  transition: width 0.3s ease-in-out;

  &__body {
    position: relative;
    height: 100%;
    overflow: auto;
  }

  .thumb-doc {
    $b: $border-solid;
    box-sizing: border-box;
    height: $doc-item-height;
    margin-bottom: -1px;
    transition: all 0.4s ease-in;

    &__hd {
      position: relative;
      display: flex;
      align-items: center;
      box-sizing: border-box;
      height: $doc-item-height;
      padding: 0 $space;
      background: white;
      border-top: $b;
      border-bottom: $b;
      cursor: pointer;
      transition: background 0.2s ease;

      &:hover {
        background: #f5f7fa;
      }

      &-icon {
        margin-right: 4px;
        color: $color-text-secondary;
        font-size: 13px;
      }

      &-text {
        flex: 1;
        font-weight: 400;
        font-size: 12px;

        @include text-ellipsis;
      }

      &-arrow {
        position: relative;
        display: none;
        margin-right: 2px;
        margin-left: -1em;
        color: $color-text-secondary;
        font-size: 12px;
        transform: scale(0.4705) rotate(-90deg);
        transition: all 0.3s;
      }

      &-count {
        position: absolute;
        bottom: -5px;
        left: 16px;
        z-index: 2;
        color: $color-text-secondary;
        font-size: 12px;
      }
    }

    &.is-open {
      // height: calc(100% - $doc-item-height);

      .thumb-doc__hd {
        &-arrow {
          transform: scale(0.4705) rotate(0);
        }
      }
    }

    &.is-active {
      .thumb-doc__hd {
        &-icon,
        &-text {
          color: $color-primary;
        }
      }
    }
  }

  &.is-only .thumb-doc.is-open {
    height: 100%;
  }

  .thumb-pages {
    height: calc(100% - $doc-item-height);
    margin: 0;
    padding: 0;
    overflow: auto;
    list-style: none;
  }

  .thumb-page {
    margin: 10px 0;

    &-img {
      position: relative;
      display: block;
      box-sizing: border-box;
      margin: 0 auto;
      background-color: #fff;
      border: 1px solid #dee0e6;
      border-radius: 1px;
      box-shadow: 0px 3px 6px 0px #e6edf7;
      cursor: pointer;
      transition: border-color 0.2s ease-in-out;

      @include imgLoadingAnimation(linear-gradient(90deg, #fff 35%, #fbfbfb 50%, #fff 65%));
    }

    &-count {
      color: #5e5f61;
      font-size: 12px;
      line-height: 2;
      text-align: center;
    }

    &.cur .thumb-page,
    &:hover .thumb-page {
      &-img {
        border-color: $color-primary;
      }

      &-count {
        color: $color-primary;
      }
    }
  }
}
</style>
